/*
============================================================================
 Name        : SBNinePatchView.cpp
 Author      : LJin
 Version     :
 Copyright   : This is LJin's Program
 Description : Application view
============================================================================
*/

// INCLUDE FILES
#include <coemain.h>
#include <eikenv.h>
#include <imageconversion.h>
#include "SBNinePatchAppView.h"
#include "SBNinePatchBuilder.h"



int TestImageDecodeL(RFs& aRFs, const TDesC& aFile, CFbsBitmap*& aBitmap,
		CFbsBitmap*& aMask)
	{
	CFbsBitmap* iBitmap = NULL; // decoded image
	CFbsBitmap* iMask = NULL;
	CImageDecoder* iImageDecoder = CImageDecoder::FileNewL(aRFs, aFile,
			CImageDecoder::EOptionAlwaysThread);
	const TFrameInfo& sFrameInfo = iImageDecoder->FrameInfo();
	TBool transparent = ((sFrameInfo.iFlags
			& TFrameInfo::ETransparencyPossible) != 0);
	if (transparent)
		{
		iMask = new CFbsBitmap();
		iMask->Create(sFrameInfo.iOverallSizeInPixels, EGray256);
		}

	iBitmap = new CFbsBitmap();

	iBitmap->Create(sFrameInfo.iOverallSizeInPixels,//EColor16MA);
			sFrameInfo.iFrameDisplayMode);

	TRequestStatus iStatus = KRequestPending;
	if (transparent)
		{
		iImageDecoder->Convert(&iStatus, *iBitmap, *iMask);
		}
	else
		{
		iImageDecoder->Convert(&iStatus, *iBitmap);
		}

	User::WaitForRequest(iStatus);

	delete iImageDecoder;

	aBitmap = iBitmap;
	aMask = iMask;
	return iStatus.Int();
	}

CFbsBitmap* MakeTwoToOne(CFbsBitmap* aBitmap, CFbsBitmap* aMask)
	{
	if(aMask == NULL)
		return NULL;
	CFbsBitmap* aOut = new CFbsBitmap();
	const TSize& aSize = aBitmap->SizeInPixels();
	aOut->Create(aSize, EColor16MA);
	int aOutBytePerLine = aSize.iWidth * 4;
	int aMainBytePerLine = aBitmap->ScanLineLength(aSize.iWidth,
			aBitmap->DisplayMode());
	int aMaskBytePerLine = aMask->ScanLineLength(aSize.iWidth,
			aMask->DisplayMode());
	aBitmap->LockHeap();
	aMask->LockHeap();
	aOut->LockHeap();

	char* aOutLine = (char*) aOut->DataAddress();
	char* aMainLine = (char*) aBitmap->DataAddress();
	char* aMaskLine = (char*) aMask->DataAddress();

	char* aOutPtr;
	char* aMainPtr;
	char* aMaskPtr;

	for (int h = 0, w; h < aSize.iHeight; ++h)
		{
		aOutPtr = aOutLine;
		aMainPtr = aMainLine;
		aMaskPtr = aMaskLine;
		for (w = 0; w < aSize.iWidth; ++w)
			{
			aOutPtr[0] = aMainPtr[0];
			aOutPtr[1] = aMainPtr[1];
			aOutPtr[2] = aMainPtr[2];
			aOutPtr[3] = *aMaskPtr;
			aOutPtr += 4;
			aMainPtr += 3;
			++aMaskPtr;
			}
		aOutLine += aOutBytePerLine;
		aMainLine += aMainBytePerLine;
		aMaskLine += aMaskBytePerLine;
		}

	aBitmap->UnlockHeap();
	aMask->UnlockHeap();
	aOut->UnlockHeap();

	return aOut;
	}

CFbsBitmap* LoadImage(const TDesC& aFile)
{
	CFbsBitmap* a1,*a2,*a3;

	TestImageDecodeL(CCoeEnv::Static()->FsSession(),aFile,a1,a2);
	a3 = MakeTwoToOne(a1,a2);
	delete a1;
	delete a2;
	return a3;
}

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CSBNinePatchAppView::NewL()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSBNinePatchAppView* CSBNinePatchAppView::NewL( const TRect& aRect )
	{
	CSBNinePatchAppView* self = CSBNinePatchAppView::NewLC( aRect );
	CleanupStack::Pop( self );
	return self;
	}

// -----------------------------------------------------------------------------
// CSBNinePatchAppView::NewLC()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSBNinePatchAppView* CSBNinePatchAppView::NewLC( const TRect& aRect )
	{
	CSBNinePatchAppView* self = new ( ELeave ) CSBNinePatchAppView;
	CleanupStack::PushL( self );
	self->ConstructL( aRect );
	return self;
	}

static TInt ThreadFunc(TAny* aParam)
{
	CSBNinePatchAppView* ss = (CSBNinePatchAppView*) aParam;
	if(ss->iPeriodic)
		ss->iPeriodic->Start(0, 1000000/30, TCallBack(CSBNinePatchAppView::PeriodicCall,ss));
	return 0;
}


// -----------------------------------------------------------------------------
// CSBNinePatchAppView::ConstructL()
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSBNinePatchAppView::ConstructL( const TRect& aRect )
	{
	// Create a window for this application view
	CreateWindowL();

	TRect sTempRect(aRect);
	sTempRect.iTl.iY = 0;
	SetRect( sTempRect );
	// Set the windows size
	//SetRect( aRect );
	//SetExtentToWholeScreen();
	
	iBitmap = new (ELeave) CWsBitmap(CEikonEnv::Static()->WsSession());

	iSrcBitmap = LoadImage(_L("c:\\ninePatch\\1.png"));
	
	iTT        = LoadImage(_L("c:\\ninePatch\\t.png"));
	
	CFbsBitmap* sdd;
	TestImageDecodeL(CCoeEnv::Static()->FsSession(),_L("c:\\ninePatch\\123.jpg"),iBg,sdd);

	iBitmap->Create (Rect().Size(),EColor16MA);
	iDevice = CFbsBitmapDevice::NewL (iBitmap );
	iDevice->CreateContext(iGc);
	
	iGc->UseFont(CCoeEnv::Static()->NormalFont());
	
	iPeriodic = CPeriodic::NewL(CActive::EPriorityLow);

	EnableDragEvents();

	// Activate the window, which makes it ready to be drawn
	ActivateL();
	
//	RThread thread;
//	
//	thread.Create(_L("abcddd"), ThreadFunc, 4096, NULL, this);
//	thread.Resume();
//	
	if(iPeriodic)
		iPeriodic->Start(0, 1000000/30, TCallBack(CSBNinePatchAppView::PeriodicCall,this));
	
	}

// -----------------------------------------------------------------------------
// CSBNinePatchAppView::CSBNinePatchAppView()
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CSBNinePatchAppView::CSBNinePatchAppView()
	{
	iIsNew = ETrue;
	}


// -----------------------------------------------------------------------------
// CSBNinePatchAppView::~CSBNinePatchAppView()
// Destructor.
// -----------------------------------------------------------------------------
//
CSBNinePatchAppView::~CSBNinePatchAppView()
	{
		delete iPeriodic;
		delete iBitmap;
		delete iDevice;
		delete iGc;
		delete iSrcBitmap;
		delete iTT;
		delete iBg;
	}


// -----------------------------------------------------------------------------
// CSBNinePatchAppView::Draw()
// Draws the display.
// -----------------------------------------------------------------------------
//
void CSBNinePatchAppView::Draw( const TRect& /*aRect*/ ) const
	{
	// Get the standard graphics context
	CWindowGc& gc = SystemGc();

	// Gets the control's extent
	//TRect drawRect( Rect());

	// Clears the screen
	//gc.Clear( drawRect );
	gc.Clear();
	
	gc.BitBlt(TPoint(),iBitmap);
	
	}

// -----------------------------------------------------------------------------
// CSBNinePatchAppView::SizeChanged()
// Called by framework when the view size is changed.
// -----------------------------------------------------------------------------
//
void CSBNinePatchAppView::SizeChanged()
	{  
	//DrawNow();
	}
	
	
void CSBNinePatchAppView::OnPeriodic()
{
	if (iIsStoped)
	{
		DrawNow();
		return;
	}
//#define SHOWORG
	
	//SBNinePatchBuilder::CleanBitmap(iBitmap);
	TRgb sdd = KRgbWhite;
	sdd.SetAlpha(0xff);
	iGc->SetBrushColor(sdd);

	iGc->Clear();
	//iGc->BitBlt(TPoint(),iBg);
#ifdef SHOWORG
	iGc->BitBlt(TPoint(),iSrcBitmap);
#endif

	CFbsBitmap* sTemp = new CFbsBitmap();

#ifdef SHOWORG
	TPoint sLeftTop(0,200);
#else
	TPoint sLeftTop(0,0);
#endif

//#define TESTTT
	
#ifdef TESTTT
	int x = sLeftTop.iX;
	int y = sLeftTop.iY;
#else
	int x = iLastPoint.iX - sLeftTop.iX;
	int y = iLastPoint.iY - sLeftTop.iY;
#endif
	
	
	
	TSize sSize(x ,y);
	if(x <= 0 || y <= 0)
		{
		//sSize.SetSize(200,300);
		sSize = iBitmap->SizeInPixels();
		sSize.iHeight -=60;
		sSize.iWidth -=60;
		//iLastPoint.SetXY(100,100);
		}

	sTemp->Create(sSize + TSize(30,30),EColor16MA);
		
	SBNinePatchBuilder::CleanBitmap(sTemp);

	const TSize& sSrcSize = iSrcBitmap->SizeInPixels();
	
	int sLeftMargin		=   17;
	int sRightMargin	=   17;
	int sTopMargin		=   59;
	int sBottomMargin	=   37;
	
	TTime sTime;
	sTime.HomeTime();
	
	if(iIsNew)		
		{
		for(int i = 0 ; i < 10; ++i)
			{
			SBNinePatchBuilder::NinePatchEx(sTemp,TRect(TPoint(10,10),sSize),iSrcBitmap,TRect(sLeftMargin,sTopMargin,sSrcSize.iWidth- sRightMargin, sSrcSize.iHeight - sBottomMargin));
			}
		}
	else
		{
		for(int i = 0 ; i < 10; ++i)
			{
			SBNinePatchBuilder::NinePatch(sTemp,TRect(TPoint(10,10),sSize),iSrcBitmap,TRect(sLeftMargin,sTopMargin,sSrcSize.iWidth- sRightMargin, sSrcSize.iHeight - sBottomMargin));
			}
		}
	
	
	TTime sNow;
	sNow.HomeTime();
	
	TBuf<32> sOutput;
	
	sOutput.AppendNum(sNow.Int64() - sTime.Int64());
	
	
#ifdef TESTTT
	SBNinePatchBuilder::FillImage(sTemp,iTT,iLastPoint - sLeftTop,iTT->SizeInPixels());
#endif
	
	
	
	iGc->BitBlt(sLeftTop,sTemp);
	
	iGc->DrawText(sOutput,TPoint(30,30));


	delete sTemp;


	DrawNow();
}

TInt CSBNinePatchAppView::PeriodicCall(TAny* aObj)
{
	static_cast<CSBNinePatchAppView*> (aObj)->OnPeriodic();
	return 1;
}

TKeyResponse CSBNinePatchAppView::OfferKeyEventL( const TKeyEvent& aKeyEvent,TEventCode aType )
{
	if (aType == EEventKey)
	{
		switch (aKeyEvent.iScanCode)
		{
		case EStdKeyDevice3://center key
		case EStdKeySpace:
			iIsStoped = !iIsStoped;
			break;
		case EStdKeyUpArrow:
			iLastPoint.iY-=10;
			break;
		case EStdKeyDownArrow:
			iLastPoint.iY+=10;
			break;
		case EStdKeyLeftArrow:
			iLastPoint.iX-=10;
			break;
		case EStdKeyRightArrow:
			iLastPoint.iX+=10;
			break;
			
		}
	}

	return EKeyWasNotConsumed;
}

void CSBNinePatchAppView::HandlePointerEventL( const TPointerEvent& aPointerEvent )
{
	iLastPoint = aPointerEvent.iPosition;
}

// End of File
